package com.tyros.common.secure.digest;

import com.tyros.common.secure.CryptoException;
import com.tyros.common.secure.GlobalProvider;
import com.tyros.common.secure.codec.Codec;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;

/**
 * 摘要工具类
 *
 * @author zsy
 */
public class DigestKit {

    public static final String SHA_256 = "SHA-256";

    /**
     * 生成摘要二进制
     *
     * @param algorithm 摘要算法名称,如SHA-256
     * @param rawData   原始内容
     * @param provider  加密算法提供者,默认为null
     * @return 加密后二进制 byte[]
     */
    public static byte[] digest(String algorithm, byte[] rawData, Provider provider) {
        return messageDigest(algorithm, provider).digest(rawData);
    }

    /**
     * 生成摘要二进制
     *
     * @param rawData  原始内容
     * @param provider 加密算法提供者
     * @return 生成的摘要字符
     */
    public static String sha256(byte[] rawData, Codec codec, Provider provider) {
        return codec.encode(digest(SHA_256, rawData, provider));
    }

    /**
     * 生成摘要字符
     *
     * @param rawData  原始内容
     * @param provider 加密算法提供者
     * @return 加密后十六进制字符
     */
    public static String sha256Hex(byte[] rawData, Provider provider) {
        return sha256(rawData, Codec.HEX, provider);
    }

    /**
     * 生成摘要字符
     *
     * @param rawData  原始内容
     * @param provider 加密算法提供者
     * @return 加密后十六进制字符
     */
    public static String sha256Hex(String rawData, Provider provider) {
        return sha256(rawData.getBytes(StandardCharsets.UTF_8), Codec.HEX, provider);
    }

    /**
     * 生成摘要字符
     *
     * @param rawData  原始内容
     * @param provider 加密算法提供者
     * @return 加密后Base64字符
     */
    public static String sha256Base64(String rawData, Provider provider) {
        return sha256(rawData.getBytes(StandardCharsets.UTF_8), Codec.BASE64, provider);
    }

    /**
     * 生成摘要字符
     *
     * @param rawData  原始内容bytes
     * @param provider 加密算法提供者
     * @return 加密后Base64字符
     */
    public static String sha256Base64(byte[] rawData, Provider provider) {
        return sha256(rawData, Codec.BASE64, provider);
    }

    private static MessageDigest messageDigest(String algorithm, Provider provider) {
        Provider useProvider = provider == null && GlobalProvider.getDefaultProvider() != null ? GlobalProvider.getDefaultProvider() : provider;
        try {
            return (null == useProvider) ? MessageDigest.getInstance(algorithm) : MessageDigest.getInstance(algorithm, useProvider);
        } catch (NoSuchAlgorithmException e) {
            throw new CryptoException(e);
        }
    }
}
